package com.cold.legendary.bprocess;

import com.cold.legendary.bprocess.common.pool.ProcessThreadRunningPoolConfig;
import com.cold.legendary.bprocess.common.utils.ValidateBeanUtils;
import com.cold.legendary.bprocess.context.ins.BPointIns;
import com.cold.legendary.bprocess.context.manager.BProcessManager;
import com.cold.legendary.bprocess.context.run.BContext;
import com.cold.legendary.bprocess.db.enums.BizStatusEnum;
import com.cold.legendary.bprocess.db.model.TbProcessRequest;
import com.cold.legendary.bprocess.db.repository.ProcessRequestRepository;
import com.cold.legendary.bprocess.trigger.BProcessTriggerService;
import com.cold.legendary.bprocess.trigger.BProcessTriggerServiceFactory;
import com.cold.legendary.bprocess.trigger.enums.TriggerModeEnum;
import com.cold.legendary.bprocess.trigger.helper.ProcessRequestCheckHelper;
import com.cold.legendary.bprocess.trigger.transaction.BProcessTransactionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author cold
 * @since 2023/3/9
 */
@Slf4j
@Service
public class BProcessService {
    @Resource
    private ProcessRequestRepository processRequestRepository;
    @Resource
    private BProcessTransactionService bProcessTransactionService;
    @Resource
    private BProcessTriggerServiceFactory factory;
    @Resource
    private ProcessRequestCheckHelper processRequestCheckHelper;

    /**
     * 开启流程
     *
     * @param bContext 上下文
     * @return 流程请求主键id
     */
    public String startBProcess(BContext bContext) {

        //校验参数合法性
        ValidateBeanUtils.validateAnnotation(bContext);

        String bizId = bContext.getBizId();
        String merchantId = bContext.getMerchantId();
//        String bizScene = bContext.getBizScene();
        String processId = bContext.getProcessId();

        //先进行幂等判断
        TbProcessRequest tbProcessRequest = processRequestRepository.queryTbProcessRequest(bizId, merchantId, processId);
        if (null != tbProcessRequest) {
            log.info("流程已经存在记录,不再重复开启流程!bizId={}, merchantId={},processId={}", bizId, merchantId, processId);
            return tbProcessRequest.getRequestId();
        }

        //不存在记录,开启流程
        if(null == bContext.getBizStatusEnum()) {
            bContext.setBizStatusEnum(BizStatusEnum.PROCESSING);
        }
        BPointIns startBPointIns = BProcessManager.getStartPoint(processId);
        String requestId = bProcessTransactionService.initPoint(bContext, startBPointIns);
        bContext.setRequestId(requestId);

        //异步线程执行业务
        ProcessThreadRunningPoolConfig.getInstance().getBProcessRunningPool().execute(() -> {
            BProcessTriggerService bProcessTriggerService = factory.getBProcessTriggerService(TriggerModeEnum.EXECUTE);
            bProcessTriggerService.triggerBPoint(startBPointIns, bContext);
        });

        TbProcessRequest qryProcessRequest = processRequestRepository.queryTbProcessRequest(requestId);
        return qryProcessRequest.getRequestId();
    }


    /**
     * 继续驱动等待的流程
     * 一般情况下,是等待异步回调的场景使用,异步回调的时候,需要明确知道需要驱动哪个pointId,防止驱动其他节点
     *
     * @param bContext 上下文
     * @return 流程主键id
     */
    public String continueBProcess(BContext bContext) {
        //基础校验
        TbProcessRequest qryProcessRequest = processRequestCheckHelper.checkProcessRequest(bContext);

        String processId = bContext.getProcessId();
        String pointId = bContext.getPointId();
        bContext.setRequestId(qryProcessRequest.getRequestId());

        BPointIns continueBPointIns = BProcessManager.getCurBPointIns(processId, pointId);

        BProcessTriggerService bProcessTriggerService = factory.getBProcessTriggerService(TriggerModeEnum.CONTINUE);
        bProcessTriggerService.triggerBPoint(continueBPointIns, bContext);

        return qryProcessRequest.getRequestId();

    }

    /**
     * 中断当前节点流程
     * 一般情况下,是失败的业务场景使用,需要明确知道需要结束哪个pointId
     *
     * @param bContext 上下文
     * @return 流程请求id
     */
    public String interruptBProcess(BContext bContext) {
        //基础校验
        TbProcessRequest qryProcessRequest = processRequestCheckHelper.checkProcessRequest(bContext);

        String processId = bContext.getProcessId();
        String pointId = bContext.getPointId();

        bContext.setRequestId(qryProcessRequest.getRequestId());

        BPointIns finishBPointIns = BProcessManager.getCurBPointIns(processId, pointId);
        BProcessTriggerService bProcessTriggerService = factory.getBProcessTriggerService(TriggerModeEnum.INTERRUPT);
        bProcessTriggerService.triggerBPoint(finishBPointIns, bContext);

        return qryProcessRequest.getRequestId();
    }
}
